package lk.icta.common.web;
/**

 @author Tharanga Punchihewa
 */

import lk.icta.common.AppConstants;
import lk.icta.common.dao.*;
import lk.icta.common.entity.District;
import lk.icta.common.entity.RailwayTrack;
import lk.icta.core.dao.LocalAuthorityDAO;
import lk.icta.core.entity.LocalAuthority;
import lk.icta.user.entity.User;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

public class JSONDivisionLookupService extends HttpServlet {

    private static final Logger logger = LoggerFactory.getLogger(JSONDivisionLookupService.class);
    private final ObjectMapper mapper = new ObjectMapper();

    private DistrictDAO districtDAO;
    private DSDivisionDAO dsDivisionDAO;
    private GNDivisionDAO gnDivisionDAO;
    private LocalAuthorityDAO localAuthorityDAO;
    private RailwayProtectionZoneDAO rpZoneDAO;
    private IPWZoneDAO ipwZoneDAO;
    private RailwayStationDAO railwayStationDAO;
    private RailwayTrackDAO railwayTrackDAO;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());

        districtDAO = (DistrictDAO) context.getBean("districtDAO");
        dsDivisionDAO = (DSDivisionDAO) context.getBean("dsDivisionDAO");
        gnDivisionDAO = (GNDivisionDAO) context.getBean("gnDivisionDAO");
        localAuthorityDAO = (LocalAuthorityDAO) context.getBean("localAuthorityDAO");
        rpZoneDAO = (RailwayProtectionZoneDAO) context.getBean("railwayProtectionZoneDAO");
        ipwZoneDAO = (IPWZoneDAO) context.getBean("ipwZoneDAO");
        railwayStationDAO = (RailwayStationDAO) context.getBean("railwayStationDAO");
        railwayTrackDAO = (RailwayTrackDAO) context.getBean("railwayTrackDAO");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String id = request.getParameter(WebConstants.DIVISION_ID);
        String mode = request.getParameter(WebConstants.MODE);

        logger.debug("Received Division Id and mode : {} {}", id, mode);
       // String lang;
        User user;
        HashMap<String, Object> optionLists;
        try {
            HttpSession session = request.getSession();
            user = (User) session.getAttribute(AppConstants.SESSION_USER_BEAN);
            Locale locale = (Locale) session.getAttribute(WebConstants.SESSION_USER_LANG);
            String language = locale.getLanguage();

            int divisionId = Integer.parseInt(id);
            optionLists = new HashMap<String, Object>();
            logger.info("selected district : {}", id);
            if ("1".equals(mode)) {
                //optionLists.put("districtsList", getDistricts(language, divisionId, user));
                optionLists.put("rpZoneList", getRPZones(language, divisionId, user));
                logger.debug("Number of  Railway Protection Zone : {}", optionLists.size());
            } else if ("2".equals(mode)) {
                //optionLists.put("dsDivisionList", getDSDivisions(language, divisionId, user));
                optionLists.put("ipwZoneList", getIPWZones(language, divisionId, user));
                logger.debug("Number of IPW Zones : {}", optionLists.size());
            } else if ("3".equals(mode)) {
                // passing Province id and return district list
                optionLists.put("railStationList", getRailwayStations(language, divisionId, user));
                logger.debug("Number of Railway Stations : {}", optionLists.size());
            } else if ("4".equals(mode)){
                optionLists.put("dsDivisionList", getDSDivisionsForOnlineUsers(language, divisionId));
                logger.debug("Number of gn divisions : {}", optionLists.size());
            } else if ("5".equals(mode)){
                optionLists.put("localAuthorityList", getLocalAuthority(language, divisionId, user));
                logger.debug("Number of local authorities for ds id {} is : {}", divisionId, optionLists.size());
            } else if ("6".equals(mode)){
                optionLists.put("districtList", getDistricts(language, divisionId, user));
                logger.debug("Number of  Districts : {}", optionLists.size());
            }else {
                List ds = getDSDivisions(language, divisionId, user);
                int dsDivisionId = Integer.parseInt(((SelectOption) ds.get(0)).getOptionValue());
                List gn = getGNDivisions(language, dsDivisionId, user);
                optionLists.put("dsDivisionList", ds);
                optionLists.put("gnDivisionList", gn);
            }
        } catch (Exception e) {
            logger.error("Fatal Error : {}", e);
            return;
        }

        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = response.getWriter();

        mapper.writeValue(out, optionLists);
        out.flush();
    }

    private List getRailwayStations(String language, int ipwId, User user) {
        Map<Integer, String> rpZoneList = railwayStationDAO.getAllIPWZoneNamesByIPWId(ipwId, language, user);
        logger.debug("lookup {} IPW Zones by Railway Track Id : {}", rpZoneList.size(), ipwId);
        logger.debug("Loaded IPW Zone list by Railway Track Id : {}", ipwId);
        return getList(rpZoneList);
    }

    private List getIPWZones(String language, int trackId, User user) {
        Map<Integer, String> rpZoneList = ipwZoneDAO.getAllIPWZoneNamesByTrackId(trackId, language, user);
        logger.debug("lookup {} IPW Zones by Railway Track Id : {}", rpZoneList.size(), trackId);
        logger.debug("Loaded IPW Zone list by Railway Track Id : {}", trackId);
        return getList(rpZoneList);
    }

    private List getRPZones(String language, int trackId, User user) {
        Map<Integer, String> rpZoneList = rpZoneDAO.getAllRPZoneNamesByTrackId(trackId, language, user);
        logger.debug("lookup {} Railway Protection Zone by Railway Track Id : {}", rpZoneList.size(), trackId);
        logger.debug("Loaded Railway Protection Zone list by Railway Track Id : {}", trackId);
        return getList(rpZoneList);
    }

    private List getDistricts(String language, int trackId, User user) {
        RailwayTrack rt = railwayTrackDAO.getRailwayTrackById(trackId);
        Map<Integer, String> districtList = new HashMap<Integer, String>();
        for(District d : rt.getDistrict()){
            districtList.put(d.getId(), d.getDistrictNameByLanguage(language));
        }
        logger.debug("lookup {} district by railway track id  : {}", districtList.size() , trackId);
        logger.debug("Loaded District list by railway track id : {}", trackId);
        return getList(districtList);
    }

    private List getDSDivisions(String language, int divisionId, User user) {
        Map<Integer, String> dsDivisionList = dsDivisionDAO.getDSDivisionNamesByDistrictId(divisionId, language, user);
        logger.debug("lookup {} ds divisions by district id  : {}", dsDivisionList.size(), divisionId);
        logger.debug("Loaded Ds Division list by District id : {}", divisionId);
        return getList(dsDivisionList);
    }

    private List getGNDivisions(String language, int divisionId, User user) {
        Map<Integer, String> gnDivisionList = gnDivisionDAO.getGNDivisionNamesByDsDivisionId(divisionId, language, user);
        logger.debug("lookup {} G.N divisions by D.S divisions id  : {}", gnDivisionList.size(), divisionId);
        return getList(gnDivisionList);
    }

    private List getDSDivisionsForOnlineUsers(String language, int divisionId) {
        Map<Integer, String> dsDivisionList = dsDivisionDAO.getDSDivisionNamesByDistrictId(divisionId, language);
        logger.debug("lookup {} ds divisions by district id  : {}", dsDivisionList.size(), divisionId);
        logger.debug("Loaded Ds Division list by District id : {}", divisionId);
        return getList(dsDivisionList);
    }

    private List getLocalAuthority(String language, int divisionId, User user) {
        List<LocalAuthority> localAuthorityList = localAuthorityDAO.getLocalAuthorityForDSDivisionByDSDivisionId(divisionId, user);
        logger.debug("lookup {} ds divisions by district id  : {}", localAuthorityList.size(), divisionId);
        logger.debug("Loaded Ds Division list by District id : {}", divisionId);
        return getListForLocalAuthority(localAuthorityList,language);
    }

    private List getList(Map<Integer, String> map) {
        List<SelectOption> ds = new ArrayList<SelectOption>();
        for (Map.Entry<Integer, String> e : map.entrySet()) {
            SelectOption option = new SelectOption();
            option.setOptionValue(e.getKey().toString());
            option.setOptionDisplay(e.getValue());
            ds.add(option);
        }
        return ds;
    }

    private List getListForLocalAuthority (List<LocalAuthority> list ,String language) {
        List<SelectOption> ds = new ArrayList<SelectOption>();
        int i = 0;
        for (LocalAuthority la : list) {
            logger.debug("Local authority id = {} and name = {} ", la.getId(), la.getSiName());
            SelectOption option = new SelectOption();
            option.setOptionValue(String.valueOf(la.getId()));
            if (AppConstants.SINHALA.equals(language)) {
                option.setOptionDisplay(String.valueOf(la.getSiName() + " " + la.getLocalAuthorityType().getSiName()));
            } else if (AppConstants.ENGLISH.equals(language)) {
                option.setOptionDisplay(String.valueOf(la.getEnName() + " " + la.getLocalAuthorityType().getEnName()));
            } else if (AppConstants.TAMIL.equals(language)) {
                option.setOptionDisplay(String.valueOf(la.getTaName() + " " + la.getLocalAuthorityType().getTaName()));
            }
            ds.add(option);
        }
        return ds;
    }
}

